package com.nodecollege.cloud.service.impl;

import com.nodecollege.cloud.common.constants.NCConstants;
import com.nodecollege.cloud.common.exception.UpmsException;
import com.nodecollege.cloud.common.model.QueryVO;
import com.nodecollege.cloud.common.model.po.*;
import com.nodecollege.cloud.common.model.vo.MenuTreeVO;
import com.nodecollege.cloud.common.utils.NCUtils;
import com.nodecollege.cloud.dao.mapper.*;
import com.nodecollege.cloud.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 菜单管理
 *
 * @author LC
 * @date 2020/1/3 23:03
 */
@Service
public class MenuServiceImpl implements MenuService {

    @Autowired
    private UpmsMenuMapper upmsMenuMapper;

    @Autowired
    private UpmsAppMapper upmsAppMapper;

    @Autowired
    private UpmsTenantMapper upmsTenantMapper;

    @Autowired
    private UpmsApiMapper upmsApiMapper;

    @Autowired
    private UpmsRoleMenuMapper upmsRoleMenuMapper;

    @Autowired
    private UpmsOpRoleMenuMapper opRoleMenuMapper;

    /**
     * 获取菜单列表
     *
     * @return
     */
    @Override
    public List<UpmsMenu> getMenuList(UpmsMenu upmsMenu) {
        NCUtils.nullOrEmptyThrow(upmsMenu.getMenuSource(), new UpmsException("-1", "菜单来源必填！"));
        if (NCConstants.INT_0.equals(upmsMenu.getMenuSource())) {
            NCUtils.nullOrEmptyThrow(upmsMenu.getAppId(), new UpmsException("-1", "应用id必填！"));
            if (NCUtils.isNullOrEmpty(upmsMenu.getTenantId())) {
                // 运维管理，应用管理，查询预制菜单 入参 appId
                return upmsMenuMapper.selectListByMap(new QueryVO<>(upmsMenu).toMap());
            } else {
                // 运维管理，租户管理，应用管理，查询租户开通的应用下开通的菜单信息 入参 appId menuSource tenantId
                return upmsMenuMapper.selectListByTenantId(new QueryVO<>(upmsMenu).toMap());
            }
        } else {
            // 系统管理，菜单管理，查询租户开通的系统菜单 和 自定义菜单 信息 入参 tenantId
            NCUtils.nullOrEmptyThrow(upmsMenu.getTenantId(), new UpmsException("-1", "租户id必填！"));
            upmsMenu.setMenuSource(null);
            upmsMenu.setAppId(null);
            return upmsMenuMapper.selectListByTenantId(new QueryVO<>(upmsMenu).toMap());
        }
    }

    /**
     * 查询菜单树
     *
     * @param upmsMenu
     * @return
     */
    @Override
    public List<MenuTreeVO> getMenuTree(UpmsMenu upmsMenu) {
        return MenuTreeVO.getMenuTree(getMenuList(upmsMenu));
    }

    /**
     * 添加菜单
     *
     * @param upmsMenu
     */
    @Override
    public void addMenu(UpmsMenu upmsMenu) {
        NCUtils.nullOrEmptyThrow(upmsMenu.getMenuSource(), new UpmsException("-1", "菜单来源必填！"));
        Integer menuType = upmsMenu.getMenuType();
        Integer menuSource = upmsMenu.getMenuSource();
        if (NCConstants.INT_0.equals(menuSource)) {
            // 运维系统添加菜单
            NCUtils.nullOrEmptyThrow(upmsMenu.getAppId(), new UpmsException("-1", "应用id必填！"));
            UpmsApp exApp = upmsAppMapper.selectByPrimaryKey(upmsMenu.getAppId());
            NCUtils.nullOrEmptyThrow(exApp, new UpmsException("-1", "应用不存在！"));
        } else {
            // 租户自定义菜单
            NCUtils.nullOrEmptyThrow(upmsMenu.getTenantId(), new UpmsException("-1", "租户id必填！"));
            UpmsTenant exTenant = upmsTenantMapper.selectByPrimaryKey(upmsMenu.getTenantId());
            NCUtils.nullOrEmptyThrow(exTenant, new UpmsException("-1", "租户不存在！"));
            if (exTenant.getTenantId().equals(upmsMenu.getTenantId())) {
                throw new UpmsException("", "租户不存在！");
            }
        }
        // 校验菜单信息
        checkMenu(upmsMenu);
        UpmsMenu query = new UpmsMenu();
        List<UpmsMenu> exMenuList = new ArrayList<>();
        if (NCConstants.INT_0.equals(menuType) || NCConstants.INT_1.equals(menuType)) {
            query.setPath(upmsMenu.getPath());
            exMenuList = upmsMenuMapper.selectListByMap(new QueryVO<>(query).toMap());
            NCUtils.notNullOrNotEmptyThrow(exMenuList, new UpmsException("", "菜单路径已使用！"));
        }
        upmsMenuMapper.insertSelective(upmsMenu);
    }

    /**
     * 更新菜单
     *
     * @param upmsMenu
     */
    @Override
    public void updateMenu(UpmsMenu upmsMenu) {
        NCUtils.nullOrEmptyThrow(upmsMenu.getMenuId(), new UpmsException("-1", "菜单id必填！"));
        NCUtils.nullOrEmptyThrow(upmsMenu.getMenuSource(), new UpmsException("-1", "菜单来源必填！"));
        if (NCConstants.INT_1.equals(upmsMenu.getMenuSource())) {
            NCUtils.nullOrEmptyThrow(upmsMenu.getTenantId(), new UpmsException("", "租户id必填！"));
        }
        UpmsMenu exMenu = upmsMenuMapper.selectByPrimaryKey(upmsMenu.getMenuId());
        NCUtils.nullOrEmptyThrow(exMenu, new UpmsException("", "菜单不存在！"));
        if (!exMenu.getMenuSource().equals(upmsMenu.getMenuSource())) {
            throw new UpmsException("", "不能操作该类型菜单！");
        }

        Integer menuType = exMenu.getMenuType();
        Integer menuSource = exMenu.getMenuSource();
        if (NCUtils.isNotNullOrNotEmpty(upmsMenu.getPath())
                && (NCConstants.INT_0.equals(menuType) || NCConstants.INT_1.equals(menuType))) {
            UpmsMenu query = new UpmsMenu();
            query.setPath(upmsMenu.getPath());
            List<UpmsMenu> exMenuList = upmsMenuMapper.selectListByMap(new QueryVO<>(query).toMap());
            if (exMenuList.size() == 1 && !exMenuList.get(0).getMenuId().equals(upmsMenu.getMenuId())) {
                throw new UpmsException("", "菜单路径已使用！");
            }
        }

        UpmsMenu updateMenu = new UpmsMenu();
        updateMenu.setMenuId(upmsMenu.getMenuId());
        updateMenu.setMenuName(upmsMenu.getMenuName());
        updateMenu.setMenuCode(upmsMenu.getMenuCode());
        updateMenu.setPath(upmsMenu.getPath());
        updateMenu.setIcon(upmsMenu.getIcon());
        updateMenu.setNum(upmsMenu.getNum());
        if (NCConstants.INT_2.equals(menuType) || NCConstants.INT_3.equals(menuType)) {
            updateMenu.setApplicationName(updateMenu.getApplicationName());
            updateMenu.setApiUrl(updateMenu.getApiUrl());
            if (NCConstants.INT_0.equals(menuSource) && NCUtils.isNotNullOrNotEmpty(upmsMenu.getApiId())) {
                UpmsApi exApi = upmsApiMapper.selectByPrimaryKey(upmsMenu.getApiId());
                NCUtils.nullOrEmptyThrow(exApi, new UpmsException("", "该接口不存在！"));
                updateMenu.setApiId(exApi.getApiId());
                updateMenu.setApplicationName(exApi.getApplicationName());
                updateMenu.setApiUrl(exApi.getApiUrl());
            }
        }

        updateMenu.setState(null);
        upmsMenuMapper.updateByPrimaryKeySelective(updateMenu);
    }

    /**
     * 删除菜单
     *
     * @param upmsMenu
     */
    @Override
    public void delMenu(UpmsMenu upmsMenu) {
        NCUtils.nullOrEmptyThrow(upmsMenu.getMenuId(), new UpmsException("-1", "菜单id必填！"));
        NCUtils.nullOrEmptyThrow(upmsMenu.getMenuSource(), new UpmsException("-1", "菜单来源必填！"));
        if (NCConstants.INT_1.equals(upmsMenu.getMenuSource())) {
            NCUtils.nullOrEmptyThrow(upmsMenu.getTenantId(), new UpmsException("", "租户id必填！"));
        }
        UpmsMenu exMenu = upmsMenuMapper.selectByPrimaryKey(upmsMenu.getMenuId());
        NCUtils.nullOrEmptyThrow(exMenu, new UpmsException("", "菜单不存在！"));
        if (!exMenu.getMenuSource().equals(upmsMenu.getMenuSource())) {
            throw new UpmsException("", "不能操作该类型菜单！");
        }

        // 查询是否有下级菜单
        UpmsMenu queryMenu = new UpmsMenu();
        queryMenu.setParentId(upmsMenu.getMenuId());
        List<UpmsMenu> exChildrenList = upmsMenuMapper.selectListByMap(new QueryVO<>(queryMenu).toMap());
        NCUtils.notNullOrNotEmptyThrow(exChildrenList, new UpmsException("-1", "该菜单存在下级菜单，不能删除！"));

        // 查询绑定角色信息
        UpmsRoleMenu queryRoleMenu = new UpmsRoleMenu();
        queryRoleMenu.setMenuId(upmsMenu.getMenuId());
        List<UpmsRoleMenu> exRoleList = upmsRoleMenuMapper.selectListByRoleMenu(queryRoleMenu);
        NCUtils.notNullOrNotEmptyThrow(exRoleList, new UpmsException("", "该菜单存在绑定的角色信息，不能删除！"));

        UpmsOpRoleMenu queryOpRole = new UpmsOpRoleMenu();
        queryOpRole.setMenuId(exMenu.getMenuId());
        List<UpmsOpRoleMenu> opRoleMenuList = opRoleMenuMapper.selectListByOpRoleMenu(queryOpRole);
        NCUtils.notNullOrNotEmptyThrow(opRoleMenuList, new UpmsException("", "改菜单存在绑定运营角色，不能删除！"));

        UpmsMenu delMenu = new UpmsMenu();
        delMenu.setMenuId(exMenu.getMenuId());
        delMenu.setState(NCConstants.INT_NEGATIVE_1);
        upmsMenuMapper.updateByPrimaryKeySelective(delMenu);
    }

    /**
     * 锁定菜单
     *
     * @param upmsMenu
     */
    @Override
    public void lockMenu(UpmsMenu upmsMenu) {
        NCUtils.nullOrEmptyThrow(upmsMenu.getMenuId(), new UpmsException("-1", "菜单id必填！"));
        NCUtils.nullOrEmptyThrow(upmsMenu.getMenuSource(), new UpmsException("-1", "菜单来源必填！"));
        if (NCConstants.INT_1.equals(upmsMenu.getMenuSource())) {
            NCUtils.nullOrEmptyThrow(upmsMenu.getTenantId(), new UpmsException("", "租户id必填！"));
        }
        UpmsMenu exMenu = upmsMenuMapper.selectByPrimaryKey(upmsMenu.getMenuId());
        NCUtils.nullOrEmptyThrow(exMenu, new UpmsException("", "菜单不存在！"));
        if (!exMenu.getMenuSource().equals(upmsMenu.getMenuSource())) {
            throw new UpmsException("", "不能操作该类型菜单！");
        }

        if (upmsMenu.getState().equals(exMenu.getState())) {
            throw new UpmsException("-1", NCConstants.INT_2.equals(exMenu.getState()) ? "菜单已禁用！" : "菜单已启用！");
        }

        UpmsMenu lockMenu = new UpmsMenu();
        lockMenu.setMenuId(exMenu.getMenuId());
        lockMenu.setState(upmsMenu.getState());
        upmsMenuMapper.updateByPrimaryKeySelective(lockMenu);
    }

    /**
     * 校验菜单规则
     *
     * @param upmsMenu
     */
    private void checkMenu(UpmsMenu upmsMenu) {
        NCUtils.nullOrEmptyThrow(upmsMenu.getMenuCode(), new UpmsException("-1", "菜单代码必填！"));
        NCUtils.nullOrEmptyThrow(upmsMenu.getMenuName(), new UpmsException("-1", "菜单名称必填！"));
        NCUtils.nullOrEmptyThrow(upmsMenu.getMenuType(), new UpmsException("-1", "菜单类型必填！"));
        Integer menuType = upmsMenu.getMenuType();
        if (menuType < NCConstants.INT_0 || menuType > NCConstants.INT_3) {
            throw new UpmsException("-1", "菜单类型错误！");
        }
        if (NCConstants.INT_1.equals(menuType) || NCConstants.INT_0.equals(menuType)) {
            NCUtils.nullOrEmptyThrow(upmsMenu.getPath(), new UpmsException("", "功能页面path必填！"));
        }
        if ((NCConstants.INT_2.equals(menuType) || NCConstants.INT_3.equals(menuType))) {
            if (NCConstants.INT_0.equals(upmsMenu.getMenuSource())) {
                NCUtils.nullOrEmptyThrow(upmsMenu.getApiId(), new UpmsException("-1", "按钮资源接口id必填！"));
                UpmsApi exApi = upmsApiMapper.selectByPrimaryKey(upmsMenu.getApiId());
                NCUtils.nullOrEmptyThrow(exApi, new UpmsException("-1", "接口不存在！"));
                upmsMenu.setApplicationName(exApi.getApplicationName());
                upmsMenu.setApiUrl(exApi.getApiUrl());
            }
            NCUtils.nullOrEmptyThrow(upmsMenu.getApplicationName(), new UpmsException("-1", "按钮资源接口应用名称必填！"));
            NCUtils.nullOrEmptyThrow(upmsMenu.getApiUrl(), new UpmsException("-1", "按钮资源接口地址必填！"));
        }
        if (upmsMenu.getParentId() != 0) {
            UpmsMenu parentMenu = upmsMenuMapper.selectByPrimaryKey(upmsMenu.getParentId());
            NCUtils.nullOrEmptyThrow(parentMenu, new UpmsException("", "父级菜单不存在！"));

            Integer parentType = parentMenu.getMenuType();
            if (NCConstants.INT_0.equals(parentType) && NCConstants.INT_2 < menuType) {
                throw new UpmsException("", "分类导航资源下只能新建分类导航或者功能页面资源！");
            }
            if (NCConstants.INT_1.equals(parentType) && !NCConstants.INT_2.equals(menuType)) {
                throw new UpmsException("", "功能页面资源下只能新建查询类按钮！");
            }
            if (NCConstants.INT_2.equals(parentType) && NCConstants.INT_2 > menuType) {
                throw new UpmsException("", "查询类按钮资源下只能新建查询类、操作类按钮！");
            }
            if (NCConstants.INT_3.equals(parentType)) {
                throw new UpmsException("-1", "不能在操作类按钮下新建资源！");
            }
        } else {
            if (!NCConstants.INT_0.equals(menuType)) {
                throw new UpmsException("", "父级菜单不存在的情况下，只能新建分类导航栏资源！");
            }
            if (NCConstants.INT_1.equals(menuType)) {
                throw new UpmsException("", "功能页面资源必须新建在分类导航资源下！");
            }
            if (NCConstants.INT_2 <= menuType) {
                throw new UpmsException("", "按钮资源必须新建在功能页面资源下！");
            }
        }
    }
}
